package com.xxcxcxcx.xc_moremob.common.entities.common_mob.basemob.rocket_zombie;

import com.google.common.collect.Lists;
import com.xxcxcxcx.xc_moremob.Main;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.Difficulty;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.monster.RangedAttackMob;
import net.minecraft.world.entity.npc.AbstractVillager;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.*;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;

import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Predicate;


public class RocketZombieEntity extends Monster implements IAnimatable, RangedAttackMob {
    //定义一个动画事件处理器
    private AnimationFactory factory = new AnimationFactory(this);
    private boolean canBreakDoors;
    public boolean IsBabyRemote;
    public boolean playAttackAnimation = false;
    public int attackTick=1;
    //枚举攻击状态
    public static final EntityDataAccessor<Integer> STATE = SynchedEntityData.defineId(RocketZombieEntity.class, EntityDataSerializers.INT);
    //打破大门的可能
    private final BreakDoorGoal breakDoorGoal = new BreakDoorGoal(this, DOOR_BREAKING_PREDICATE);
    private static final Predicate<Difficulty> DOOR_BREAKING_PREDICATE = (mode) -> {
        return mode == Difficulty.HARD || mode == Difficulty.NORMAL;
    };
    protected boolean isSunSensitive() {
        return true;
    }
    public void aiStep() {
        if (this.isAlive()) {
            boolean flag = this.isSunSensitive() && this.isSunBurnTick();
            if (flag) {
                this.setSecondsOnFire(8);
            }
        }
        super.aiStep();
    }
    public RocketZombieEntity(EntityType<? extends Monster> type, Level worldIn) {
        super(type, worldIn);
        this.xpReward = 10;
        this.setBaby(worldIn.getRandom().nextFloat()<0.05F);
    }

    protected void registerGoals() {
        this.goalSelector.addGoal(1, new RocketRemoteAttackGoal(this, 1.0D, 20, 15.0F,1));
        this.goalSelector.addGoal(2, new AttackGoal(this, 1.0D, false));
        this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
        this.goalSelector.addGoal(7, new FloatGoal(this));
        this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
        this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
        this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));

    }
    public static AttributeSupplier.Builder prepareAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, 20.0d).
                add(Attributes.MOVEMENT_SPEED, (double)0.22F).
                add(Attributes.ATTACK_DAMAGE, 2.0);
    }

    //伤害函数
    public boolean doHurtTarget(Entity entityIn) {
        if(!super.doHurtTarget(entityIn))
        {
            this.playAttackAnimation=false;
            return false;
        }
        else{
            setAttackingState(2);
            return true;
        }

    }
    //该状态播放器控制生物平时的各种动作
    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
        //生物在移动，就播放移动的动画，路径和第2步的动作字符串对应
        if (event.isMoving()) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("moveing", true));
            return PlayState.CONTINUE;
        }
        //不动的话就播放闲置时的动画
        event.getController().setAnimation(new AnimationBuilder().addAnimation("standby", true));
        return PlayState.CONTINUE;
    }

    //该状态播放器控制生物攻击时的各种动作
    private <E extends IAnimatable> PlayState predicate1(AnimationEvent<E> event) {
        //如果生物攻击状态为1并且没有死亡，就执行这个攻击动画
        if (this.entityData.get(STATE) == 1 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("rocketattack", true));
            return PlayState.CONTINUE;
        }else if (this.entityData.get(STATE) == 2 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("meleeattack", true));
            return PlayState.CONTINUE;
        }
        return PlayState.STOP;
    }
    //将我们之前的所有动画控制器进行注册
    @Override
    public void registerControllers(AnimationData data) {
        data.addAnimationController(new AnimationController(this, "controller",
                0, this::predicate));
        data.addAnimationController(new AnimationController(this, "controller1",
                0, this::predicate1));
    }

    @Override
    public AnimationFactory getFactory() {
        // TODO Auto-generated method stub
        return this.factory;
    }

    //生物实体声音
    protected SoundEvent getAmbientSound() {
        return SoundEvents.ZOMBIE_AMBIENT;
    }

    protected SoundEvent getHurtSound(DamageSource source) {
        return SoundEvents.ZOMBIE_HURT;
    }

    protected SoundEvent getDeathSound() {
        return SoundEvents.ZOMBIE_DEATH;
    }

    protected void playStepSound(BlockPos pos, BlockState blockstate) {
        this.playSound(SoundEvents.ZOMBIE_STEP, 0.15F, 1.0F);
    }

    protected SoundEvent getStepSound() {
        return SoundEvents.SKELETON_STEP;
    }

    protected boolean supportsBreakDoorGoal() {
        return true;
    }
    //怪物能不能破门而入

    public void addAdditionalSaveData(CompoundTag p_34319_) {
        super.addAdditionalSaveData(p_34319_);
        p_34319_.putBoolean("IsBaby", this.isBaby());
    }

    public void readAdditionalSaveData(CompoundTag p_34305_) {
        super.readAdditionalSaveData(p_34305_);
        this.setBaby(p_34305_.getBoolean("IsBaby"));
    }
    public boolean isBaby() {
        return IsBabyRemote;
    }
    public void setBaby(boolean a){
        IsBabyRemote=a;
    }
    public int getAttckingState() {
        return this.entityData.get(STATE);
    }

    public void setAttackingState(int time) {
        this.entityData.set(STATE, time);
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(STATE, 0);
    }

    protected void populateDefaultEquipmentSlots(DifficultyInstance p_32136_) {
        super.populateDefaultEquipmentSlots(p_32136_);
        this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.BOW));
    }
    public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_32146_, DifficultyInstance p_32147_, MobSpawnType p_32148_, @Nullable SpawnGroupData p_32149_, @Nullable CompoundTag p_32150_) {
        p_32149_ = super.finalizeSpawn(p_32146_, p_32147_, p_32148_, p_32149_, p_32150_);
        this.populateDefaultEquipmentSlots(p_32147_);
        this.populateDefaultEquipmentEnchantments(p_32147_);
        return p_32149_;
    }
    public void performRangedAttack(LivingEntity p_32141_, float p_32142_) {
        this.setAttackingState(1);
        Projectile abstractarrow = this.getArrow(this, p_32142_);
        double d0 = p_32141_.getX() - this.getX();
        double d1 = p_32141_.getY() - abstractarrow.getY();
        double d2 = p_32141_.getZ() - this.getZ();
        //16F是箭速度，直接决定伤害
        abstractarrow.shoot(d0, d1, d2, 1.6F, 0);
        this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F));
        this.level.addFreshEntity(abstractarrow);
    }
    protected void AddEffect(CompoundTag compoundTag, MobEffect mobEffect,int level,int time){
        compoundTag.putInt(mobEffect.getDescriptionId()+"Level",level);
        compoundTag.putInt(mobEffect.getDescriptionId()+"Time",time);
    }
    protected Projectile getArrow(LivingEntity livingEntity, float p_32157_) {
        ItemStack itemstack = new ItemStack(Items.FIREWORK_ROCKET);
        CompoundTag DamageKind = itemstack.getOrCreateTagElement(Main.MOD_ID);
        //DamageKind.putInt("Damage",10);
        //AddEffect(DamageKind, MobEffects.POISON,1,600);
        CompoundTag fireworkstag = itemstack.getOrCreateTagElement("Fireworks");
        CompoundTag compoundtag = new CompoundTag();
        List<Integer> list = Lists.newArrayList();
        list.add(DyeColor.byId(random.nextInt(15)).getFireworkColor());
        compoundtag.putBoolean("Trail", true);
        compoundtag.putIntArray("Colors", list);
        compoundtag.putByte("Type", (byte) 1);
        fireworkstag.putByte("Flight", (byte) 10);
        ListTag listTag = new ListTag();
        listTag.add(compoundtag);
        fireworkstag.put("Explosions",listTag);
        Projectile abstractArrow = new FireworkRocketEntity(livingEntity.level,livingEntity,livingEntity.eyeBlockPosition().getX(),livingEntity.eyeBlockPosition().getY(),livingEntity.eyeBlockPosition().getZ(),itemstack);
        return abstractArrow;
    }
    //我们生物的AI，决定使用哪种攻击方式
    static class RocketRemoteAttackGoal<T extends RocketZombieEntity & RangedAttackMob> extends RangedBowAttackGoal {
        //攻击计时器
        private final T mob;
        protected int maxfight;
        protected int fight=0;
        private final double speedModifier;
        private int attackIntervalMin;
        private final float attackRadiusSqr;
        private int attackTime = -1;
        private int seeTime;
        private boolean strafingClockwise;
        private boolean strafingBackwards;
        private int strafingTime = -1;
        public <M extends Monster & RangedAttackMob> RocketRemoteAttackGoal(M p_25792_, double p_25793_, int p_25794_, float p_25795_,int num){
            super(p_25792_, p_25793_, p_25794_, p_25795_);
            mob= (T) p_25792_;
            maxfight=num;
            this.speedModifier = p_25793_;
            this.attackIntervalMin = p_25794_;
            this.attackRadiusSqr = p_25795_ * p_25795_;
        }
        public boolean canUse() {
            return super.canUse()&&(fight<maxfight);
        }
        public boolean canContinueToUse() {
            return this.canUse();
        }
        public void stop(){
            super.stop();
            mob.setAttackingState(0);
        }
        int remootetime=0;
        public void tick() {
            if(mob.getAttckingState()==1&&remootetime==0){
                remootetime=10;
            }else if(remootetime>0){
                remootetime--;
                if(remootetime==0){
                    mob.setAttackingState(0);
                }
            }
            LivingEntity livingentity = this.mob.getTarget();
            if (livingentity != null) {
                double d0 = this.mob.distanceToSqr(livingentity.getX(), livingentity.getY(), livingentity.getZ());
                boolean flag = this.mob.getSensing().hasLineOfSight(livingentity);
                boolean flag1 = this.seeTime > 0;
                if (flag != flag1) {
                    this.seeTime = 0;
                }

                if (flag) {
                    ++this.seeTime;
                } else {
                    --this.seeTime;
                }

                if (!(d0 > (double)this.attackRadiusSqr) && this.seeTime >= 20) {
                    this.mob.getNavigation().stop();
                    ++this.strafingTime;
                } else {
                    this.mob.getNavigation().moveTo(livingentity, this.speedModifier);
                    this.strafingTime = -1;
                }

                if (this.strafingTime >= 20) {
                    if ((double)this.mob.getRandom().nextFloat() < 0.3D) {
                        this.strafingClockwise = !this.strafingClockwise;
                    }

                    if ((double)this.mob.getRandom().nextFloat() < 0.3D) {
                        this.strafingBackwards = !this.strafingBackwards;
                    }

                    this.strafingTime = 0;
                }

                if (this.strafingTime > -1) {
                    if (d0 > (double)(this.attackRadiusSqr * 0.75F)) {
                        this.strafingBackwards = false;
                    } else if (d0 < (double)(this.attackRadiusSqr * 0.25F)) {
                        this.strafingBackwards = true;
                    }

                    this.mob.getMoveControl().strafe(this.strafingBackwards ? -0.5F : 0.5F, this.strafingClockwise ? 0.5F : -0.5F);
                    this.mob.lookAt(livingentity, 30.0F, 30.0F);
                } else {
                    this.mob.getLookControl().setLookAt(livingentity, 30.0F, 30.0F);
                }

                if (this.mob.isUsingItem()) {
                    if (!flag && this.seeTime < -60) {
                        this.mob.stopUsingItem();
                    } else if (flag) {
                        int i = this.mob.getTicksUsingItem();
                        if (i >= 20) {
                            this.mob.stopUsingItem();
                            fight++;
                            this.mob.performRangedAttack(livingentity, BowItem.getPowerForTime(i));
                            this.attackTime = this.attackIntervalMin;
                        }
                    }
                } else if (--this.attackTime <= 0 && this.seeTime >= -60) {
                    this.mob.startUsingItem(ProjectileUtil.getWeaponHoldingHand(this.mob, item -> item instanceof BowItem));
                }
            }
        }
    }
    static class AttackGoal extends MeleeAttackGoal {
        private final RocketZombieEntity mob2;
        //攻击计时器
        protected int raiseArmTicks = 0;

        public AttackGoal(RocketZombieEntity p_26019_, double p_26020_, boolean p_26021_) {
            super(p_26019_, p_26020_, p_26021_);
            this.mob2 = p_26019_;
        }
        public void stop(){
            mob2.setAttackingState(0);
        }
        int remootetime=0;
        public void tick() {
            super.tick();
            if(mob2.getAttckingState()==2&&remootetime==0){
                remootetime=10;
            }else if(remootetime>0){
                remootetime--;
                if(remootetime==0){
                    mob2.setAttackingState(0);
                }
            }
        }
    }
}